We will build a regressor which can use these parameters to determine the signal strength or quality [as number].
# imports
import h5py
import tensorflow
import warnings
from time import time
import seaborn as sns
from pprint import pprint
import matplotlib.pyplot as plt
import pandas as pd, numpy as np
from sklearn.model_selection import GridSearchCV, RandomizedSearchCV
warnings.filterwarnings('ignore')
%matplotlib inline
df = pd.read_csv('Part- 1,2&3 - Signal.csv')
df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 1599 entries, 0 to 1598 Data columns (total 12 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Parameter 1 1599 non-null float64 1 Parameter 2 1599 non-null float64 2 Parameter 3 1599 non-null float64 3 Parameter 4 1599 non-null float64 4 Parameter 5 1599 non-null float64 5 Parameter 6 1599 non-null float64 6 Parameter 7 1599 non-null float64 7 Parameter 8 1599 non-null float64 8 Parameter 9 1599 non-null float64 9 Parameter 10 1599 non-null float64 10 Parameter 11 1599 non-null float64 11 Signal_Strength 1599 non-null int64 dtypes: float64(11), int64(1) memory usage: 150.0 KB
df.sample(7)
| Parameter 1 | Parameter 2 | Parameter 3 | Parameter 4 | Parameter 5 | Parameter 6 | Parameter 7 | Parameter 8 | Parameter 9 | Parameter 10 | Parameter 11 | Signal_Strength | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 472 | 12.5 | 0.370 | 0.55 | 2.6 | 0.083 | 25.0 | 68.0 | 0.9995 | 3.15 | 0.82 | 10.4 | 6 |
| 343 | 10.9 | 0.390 | 0.47 | 1.8 | 0.118 | 6.0 | 14.0 | 0.9982 | 3.30 | 0.75 | 9.8 | 6 |
| 318 | 9.8 | 0.660 | 0.39 | 3.2 | 0.083 | 21.0 | 59.0 | 0.9989 | 3.37 | 0.71 | 11.5 | 7 |
| 178 | 7.0 | 0.805 | 0.00 | 2.5 | 0.068 | 7.0 | 20.0 | 0.9969 | 3.48 | 0.56 | 9.6 | 5 |
| 91 | 8.6 | 0.490 | 0.28 | 1.9 | 0.110 | 20.0 | 136.0 | 0.9972 | 2.93 | 1.95 | 9.9 | 6 |
| 1406 | 8.2 | 0.240 | 0.34 | 5.1 | 0.062 | 8.0 | 22.0 | 0.9974 | 3.22 | 0.94 | 10.9 | 6 |
| 674 | 10.8 | 0.400 | 0.41 | 2.2 | 0.084 | 7.0 | 17.0 | 0.9984 | 3.08 | 0.67 | 9.3 | 6 |
# From a completeness point of view, the data looks great and there are no missing values.
# no missing values, no need to impute or drop any data points
df.isna().sum()
Parameter 1 0 Parameter 2 0 Parameter 3 0 Parameter 4 0 Parameter 5 0 Parameter 6 0 Parameter 7 0 Parameter 8 0 Parameter 9 0 Parameter 10 0 Parameter 11 0 Signal_Strength 0 dtype: int64
df.Signal_Strength.value_counts() # 6 Unique values with imblanced classes
5 681 6 638 7 199 4 53 8 18 3 10 Name: Signal_Strength, dtype: int64
df.describe().T.style.background_gradient('Greens')
| count | mean | std | min | 25% | 50% | 75% | max | |
|---|---|---|---|---|---|---|---|---|
| Parameter 1 | 1599.000000 | 8.319637 | 1.741096 | 4.600000 | 7.100000 | 7.900000 | 9.200000 | 15.900000 |
| Parameter 2 | 1599.000000 | 0.527821 | 0.179060 | 0.120000 | 0.390000 | 0.520000 | 0.640000 | 1.580000 |
| Parameter 3 | 1599.000000 | 0.270976 | 0.194801 | 0.000000 | 0.090000 | 0.260000 | 0.420000 | 1.000000 |
| Parameter 4 | 1599.000000 | 2.538806 | 1.409928 | 0.900000 | 1.900000 | 2.200000 | 2.600000 | 15.500000 |
| Parameter 5 | 1599.000000 | 0.087467 | 0.047065 | 0.012000 | 0.070000 | 0.079000 | 0.090000 | 0.611000 |
| Parameter 6 | 1599.000000 | 15.874922 | 10.460157 | 1.000000 | 7.000000 | 14.000000 | 21.000000 | 72.000000 |
| Parameter 7 | 1599.000000 | 46.467792 | 32.895324 | 6.000000 | 22.000000 | 38.000000 | 62.000000 | 289.000000 |
| Parameter 8 | 1599.000000 | 0.996747 | 0.001887 | 0.990070 | 0.995600 | 0.996750 | 0.997835 | 1.003690 |
| Parameter 9 | 1599.000000 | 3.311113 | 0.154386 | 2.740000 | 3.210000 | 3.310000 | 3.400000 | 4.010000 |
| Parameter 10 | 1599.000000 | 0.658149 | 0.169507 | 0.330000 | 0.550000 | 0.620000 | 0.730000 | 2.000000 |
| Parameter 11 | 1599.000000 | 10.422983 | 1.065668 | 8.400000 | 9.500000 | 10.200000 | 11.100000 | 14.900000 |
| Signal_Strength | 1599.000000 | 5.636023 | 0.807569 | 3.000000 | 5.000000 | 6.000000 | 6.000000 | 8.000000 |
# !pip install exploretransform
import exploretransform as et
et.peek(df) # returns dtype, levels, # of observations, and first five observations for a dataframe
| variable | dtype | lvls | obs | head | |
|---|---|---|---|---|---|
| 0 | Parameter 1 | float64 | 96 | 1599 | [7.4, 7.8, 7.8, 11.2, 7.4] |
| 1 | Parameter 2 | float64 | 143 | 1599 | [0.7, 0.88, 0.76, 0.28, 0.7] |
| 2 | Parameter 3 | float64 | 80 | 1599 | [0.0, 0.0, 0.04, 0.56, 0.0] |
| 3 | Parameter 4 | float64 | 91 | 1599 | [1.9, 2.6, 2.3, 1.9, 1.9] |
| 4 | Parameter 5 | float64 | 153 | 1599 | [0.076, 0.098, 0.092, 0.075, 0.076] |
| 5 | Parameter 6 | float64 | 60 | 1599 | [11.0, 25.0, 15.0, 17.0, 11.0] |
| 6 | Parameter 7 | float64 | 144 | 1599 | [34.0, 67.0, 54.0, 60.0, 34.0] |
| 7 | Parameter 8 | float64 | 436 | 1599 | [0.9978, 0.9968, 0.997, 0.998, 0.9978] |
| 8 | Parameter 9 | float64 | 89 | 1599 | [3.51, 3.2, 3.26, 3.16, 3.51] |
| 9 | Parameter 10 | float64 | 96 | 1599 | [0.56, 0.68, 0.65, 0.58, 0.56] |
| 10 | Parameter 11 | float64 | 65 | 1599 | [9.4, 9.8, 9.8, 9.8, 9.4] |
| 11 | Signal_Strength | int64 | 6 | 1599 | [5.0, 5.0, 5.0, 6.0, 5.0] |
skew_stats = et.skewstats(df)
skew_stats
| dtype | skewness | magnitude | |
|---|---|---|---|
| Parameter 4 | float64 | 4.536395 | 2-high |
| Parameter 5 | float64 | 5.675017 | 2-high |
| Parameter 6 | float64 | 1.249394 | 2-high |
| Parameter 7 | float64 | 1.514109 | 2-high |
| Parameter 10 | float64 | 2.426393 | 2-high |
| Parameter 1 | float64 | 0.981829 | 1-medium |
| Parameter 2 | float64 | 0.670962 | 1-medium |
| Parameter 11 | float64 | 0.860021 | 1-medium |
| Parameter 3 | float64 | 0.318039 | 0-approx_symmetric |
| Parameter 8 | float64 | 0.071221 | 0-approx_symmetric |
| Parameter 9 | float64 | 0.193502 | 0-approx_symmetric |
| Signal_Strength | int64 | 0.217597 | 0-approx_symmetric |
skew_stats.magnitude.value_counts() # 44 features with high skew
2-high 5 0-approx_symmetric 4 1-medium 3 Name: magnitude, dtype: int64
Uni-Variate Analysis
# install sweetviz for Auto EDA
# !pip install sweetviz
# or
# !conda install -c conda-forge sweetviz
import sweetviz as sv
uni_report = sv.analyze(df, pairwise_analysis='on')
uni_report.show_notebook()
Parameter 1, 8, 9, 10 and 11 seem to have fairly normal distributions. Others do not seem to follow any distributions
Bi-Variate Analysis
# boxplots
sns.set()
for column in df.columns:
plt.figure(figsize=(10, 5))
sns.boxplot(x='Signal_Strength',y=column, data = df, hue = 'Signal_Strength')
Our dataset has outliers as per the boxplots
sns.pairplot(df) # multivariate analysis
<seaborn.axisgrid.PairGrid at 0x1cf24ec6a90>
# Correlation with heat map
corr = df.corr()
sns.set_context("notebook", font_scale=1.0, rc={"lines.linewidth": 2.5})
plt.figure(figsize=(10.5, 6))
# create a mask so we only see the correlation values once
mask = np.zeros_like(corr)
mask[np.triu_indices_from(mask, 1)] = True
a = sns.heatmap(corr,mask=mask, annot=True, fmt='.2f', cmap=sns.color_palette("rocket", as_cmap = True))
rotx = a.set_xticklabels(a.get_xticklabels(), rotation=90)
roty = a.set_yticklabels(a.get_yticklabels(), rotation=30)
From the correlations:
Hence, These parameters could be considered as noise and dropped during modeling
Train a vanilla random forest model to get feature importances:
# Calucate feature importances
def plot_feature_importance(importance, names, model_type):
""""Create arrays from feature importance and feature names"""
feature_importance = np.array(importance)
feature_names = np.array(names)
#Create a DataFrame using a Dictionary
data={'feature_names':feature_names,'feature_importance':feature_importance}
fi_df = pd.DataFrame(data)
#Sort the DataFrame in order decreasing feature importance
fi_df.sort_values(by=['feature_importance'], ascending=False,inplace=True)
#Define size of bar plot
plt.figure(figsize=(10,8))
#Plot Searborn bar chart
sns.barplot(x=fi_df['feature_importance'], y=fi_df['feature_names'])
#Add chart labels
plt.title(model_type + 'FEATURE IMPORTANCE')
plt.xlabel('FEATURE IMPORTANCE')
plt.ylabel('FEATURE NAMES')
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score,confusion_matrix
from sklearn.metrics import classification_report
from sklearn.model_selection import train_test_split, GridSearchCV, RandomizedSearchCV
from sklearn.metrics import f1_score, roc_auc_score
y = df.Signal_Strength
X = df.drop('Signal_Strength', axis=1)
from sklearn.model_selection import train_test_split
seed = 77 # for reproducibility purposes
# 70-30 train test split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3,random_state=seed)
X_train.shape, X_test.shape
((1119, 11), (480, 11))
# hyper paramter tuning
rf = RandomForestClassifier()
parameters = {'max_features': ['auto', 'sqrt'],
'n_estimators' : [100, 500, 1000, 1500, 2000, 2500, 3000, 4000, 5000, 6000],
'max_depth' : [5, 20, 45, 55, 60, 70, 100],
'bootstrap': [True, False]}
rf_rand = RandomizedSearchCV(rf, parameters, cv=10, verbose=5, n_jobs=-1)
rf_rand.fit(X_train, y_train)
Fitting 10 folds for each of 10 candidates, totalling 100 fits
RandomizedSearchCV(cv=10, estimator=RandomForestClassifier(), n_jobs=-1,
param_distributions={'bootstrap': [True, False],
'max_depth': [5, 20, 45, 55, 60, 70,
100],
'max_features': ['auto', 'sqrt'],
'n_estimators': [100, 500, 1000, 1500,
2000, 2500, 3000, 4000,
5000, 6000]},
verbose=5)
rf_rand.best_params_
{'n_estimators': 100,
'max_features': 'auto',
'max_depth': 60,
'bootstrap': True}
rf_pred = rf_rand.predict(X_test)
print(classification_report(y_test, rf_pred))
precision recall f1-score support
3 0.00 0.00 0.00 5
4 0.00 0.00 0.00 14
5 0.70 0.79 0.74 203
6 0.60 0.69 0.64 187
7 0.73 0.42 0.53 65
8 0.00 0.00 0.00 6
accuracy 0.66 480
macro avg 0.34 0.32 0.32 480
weighted avg 0.63 0.66 0.64 480
sns.set()
plot_feature_importance(rf_rand.best_estimator_.feature_importances_, X.columns, 'Random Forest ')
Hence, Looking at the correlations between the features and the target and the feature importances found from trainign a plain vanilla random forest model.
selected_df = df[['Parameter 2', 'Parameter 3', 'Parameter 5',
'Parameter 7', 'Parameter 8', 'Parameter 10',
'Parameter 11', 'Signal_Strength']]
# Correlation with heat map after feature selection
corr = selected_df.corr()
sns.set_context("notebook", font_scale=1.0, rc={"lines.linewidth": 2.5})
plt.figure(figsize=(10.5, 6))
# create a mask so we only see the correlation values once
mask = np.zeros_like(corr)
mask[np.triu_indices_from(mask, 1)] = True
a = sns.heatmap(corr,mask=mask, annot=True, fmt='.2f', cmap=sns.color_palette("rocket", as_cmap = True))
rotx = a.set_xticklabels(a.get_xticklabels(), rotation=90)
roty = a.set_yticklabels(a.get_yticklabels(), rotation=30)
Hence, Looking at the correlations after feature selection
sns.pairplot(selected_df)
<seaborn.axisgrid.PairGrid at 0x1cf2dfe39d0>
from tensorflow.keras.utils import to_categorical
# converting Signal_stregth to categorical series as we want to build a classifier instead of regressor
categorical_labels = to_categorical(selected_df['Signal_Strength'], num_classes=None)
X = selected_df.drop('Signal_Strength', axis=1)
Y = categorical_labels
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.3, random_state=seed)
X_train.shape, X_test.shape
((1119, 7), (480, 7))
from tensorflow.python.keras.models import Sequential
from tensorflow.python.keras.layers import Dense,Dropout
model = Sequential([
Dense(25, input_dim=7, kernel_initializer='he_normal', activation='relu'),
Dropout(0.21),
Dense(25, activation='relu'),
Dropout(0.21),
Dense(9, activation='softmax')
])
model.summary()
Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense (Dense) (None, 25) 200 _________________________________________________________________ dropout (Dropout) (None, 25) 0 _________________________________________________________________ dense_1 (Dense) (None, 25) 650 _________________________________________________________________ dropout_1 (Dropout) (None, 25) 0 _________________________________________________________________ dense_2 (Dense) (None, 9) 234 ================================================================= Total params: 1,084 Trainable params: 1,084 Non-trainable params: 0 _________________________________________________________________
# using mae loss because we have outliers present in our dataset and mse is not robust against outliers
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc'])
from tensorflow.python.keras.callbacks import LambdaCallback, EarlyStopping
# To simplify the log
simple_log = LambdaCallback(
on_epoch_end = lambda e, l: print(f" ~| Epoch: {e+1} | Validation Loss: {l['val_loss']:.5f}", end =" >|> \n" ))
early_stop = EarlyStopping(monitor='val_loss',
min_delta=0,
patience=10,
verbose=1,
restore_best_weights=True)
def plot_learning_curve(hist, metric='loss'):
sns.set()
plt.figure(figsize=(5, 4))
train = hist.history[metric]
val = hist.history[f'val_{metric}']
epochs_run = range(1,len(train) + 1)
sns.lineplot(epochs_run, train, marker = 'o', color = 'coral', label = 'Training')
sns.lineplot(epochs_run, val, marker = '>', color = 'green', label = 'Validation')
plt.title(f"{metric.capitalize()} vs. Epochs", fontsize = 20)
plt.legend()
plt.show()
epochs = 300
batch_size = 64
h = model.fit(X_train, y_train,
epochs=epochs,
batch_size=batch_size,
validation_split=0.2,
callbacks = [early_stop, simple_log],
verbose = False)
~| Epoch: 1 | Validation Loss: 4.48956 >|> ~| Epoch: 2 | Validation Loss: 3.47821 >|> ~| Epoch: 3 | Validation Loss: 2.75833 >|> ~| Epoch: 4 | Validation Loss: 2.39106 >|> ~| Epoch: 5 | Validation Loss: 2.23078 >|> ~| Epoch: 6 | Validation Loss: 2.22332 >|> ~| Epoch: 7 | Validation Loss: 1.93613 >|> ~| Epoch: 8 | Validation Loss: 1.61460 >|> ~| Epoch: 9 | Validation Loss: 1.44381 >|> ~| Epoch: 10 | Validation Loss: 1.33438 >|> ~| Epoch: 11 | Validation Loss: 1.34580 >|> ~| Epoch: 12 | Validation Loss: 1.32108 >|> ~| Epoch: 13 | Validation Loss: 1.29073 >|> ~| Epoch: 14 | Validation Loss: 1.28698 >|> ~| Epoch: 15 | Validation Loss: 1.27501 >|> ~| Epoch: 16 | Validation Loss: 1.22770 >|> ~| Epoch: 17 | Validation Loss: 1.19275 >|> ~| Epoch: 18 | Validation Loss: 1.17838 >|> ~| Epoch: 19 | Validation Loss: 1.15734 >|> ~| Epoch: 20 | Validation Loss: 1.14182 >|> ~| Epoch: 21 | Validation Loss: 1.13041 >|> ~| Epoch: 22 | Validation Loss: 1.12813 >|> ~| Epoch: 23 | Validation Loss: 1.13114 >|> ~| Epoch: 24 | Validation Loss: 1.12624 >|> ~| Epoch: 25 | Validation Loss: 1.11996 >|> ~| Epoch: 26 | Validation Loss: 1.13344 >|> ~| Epoch: 27 | Validation Loss: 1.12875 >|> ~| Epoch: 28 | Validation Loss: 1.13395 >|> ~| Epoch: 29 | Validation Loss: 1.12630 >|> ~| Epoch: 30 | Validation Loss: 1.12010 >|> ~| Epoch: 31 | Validation Loss: 1.12241 >|> ~| Epoch: 32 | Validation Loss: 1.12020 >|> ~| Epoch: 33 | Validation Loss: 1.11555 >|> ~| Epoch: 34 | Validation Loss: 1.11851 >|> ~| Epoch: 35 | Validation Loss: 1.12914 >|> ~| Epoch: 36 | Validation Loss: 1.12695 >|> ~| Epoch: 37 | Validation Loss: 1.12378 >|> ~| Epoch: 38 | Validation Loss: 1.11919 >|> ~| Epoch: 39 | Validation Loss: 1.11728 >|> ~| Epoch: 40 | Validation Loss: 1.11971 >|> ~| Epoch: 41 | Validation Loss: 1.11873 >|> ~| Epoch: 42 | Validation Loss: 1.12026 >|> Restoring model weights from the end of the best epoch. ~| Epoch: 43 | Validation Loss: 1.12249 >|> Epoch 00043: early stopping
plot_learning_curve(h)
loss, acc = model.evaluate(X_test, y_test)
print("Testing Accuracy: ", acc*100)
15/15 [==============================] - 0s 2ms/step - loss: 1.1991 - acc: 0.4271 Testing Accuracy: 42.70833432674408
y_pred = model.predict_classes(X_test)
y_classes = [np.argmax(y, axis=None, out=None) for y in y_test]
print(classification_report(y_pred,y_classes))
precision recall f1-score support
3 0.00 0.00 0.00 0
4 0.00 0.00 0.00 0
5 1.00 0.43 0.60 477
6 0.01 0.67 0.02 3
7 0.00 0.00 0.00 0
8 0.00 0.00 0.00 0
accuracy 0.43 480
macro avg 0.17 0.18 0.10 480
weighted avg 0.99 0.43 0.59 480
selected_df.Signal_Strength.value_counts()
5 681 6 638 7 199 4 53 8 18 3 10 Name: Signal_Strength, dtype: int64
merged_df = selected_df.copy(True)
# merge the output classes given that we have very huge imbalance in the classes
def categorise_signal(row):
if row >= 7:
return 3
elif row <=4:
return 1
else:
return 2
# binning the output classes
merged_df['Signal_Strength'] = merged_df['Signal_Strength'].apply(categorise_signal)
merged_df.Signal_Strength.value_counts()
2 1319 3 217 1 63 Name: Signal_Strength, dtype: int64
# converting Signal_stregth to categorical series as we want to build a classifier instead of regressor
categorical_labels = to_categorical(merged_df['Signal_Strength'], num_classes=None)
X = merged_df.drop('Signal_Strength', axis=1)
Y = categorical_labels
X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.3, random_state=seed)
X_train.shape, X_test.shape
((1119, 7), (480, 7))
model2 = Sequential([
Dense(100, input_dim=7, kernel_initializer='he_normal', activation='relu'),
Dense(50, activation='relu'),
Dropout(0.2),
Dense(4, activation='softmax')
])
model2.summary()
Model: "sequential_1" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense_3 (Dense) (None, 100) 800 _________________________________________________________________ dense_4 (Dense) (None, 50) 5050 _________________________________________________________________ dropout_2 (Dropout) (None, 50) 0 _________________________________________________________________ dense_5 (Dense) (None, 4) 204 ================================================================= Total params: 6,054 Trainable params: 6,054 Non-trainable params: 0 _________________________________________________________________
# using mae loss because we have outliers present in our dataset and mse is not robust against outliers
model2.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc'])
epochs = 300
batch_size = 64
h2 = model2.fit(X_train, y_train,
epochs=epochs,
batch_size=batch_size,
validation_split=0.2,
callbacks = [early_stop, simple_log],
verbose = False)
~| Epoch: 1 | Validation Loss: 1.90418 >|> ~| Epoch: 2 | Validation Loss: 1.25681 >|> ~| Epoch: 3 | Validation Loss: 1.46902 >|> ~| Epoch: 4 | Validation Loss: 0.99405 >|> ~| Epoch: 5 | Validation Loss: 0.77760 >|> ~| Epoch: 6 | Validation Loss: 0.77493 >|> ~| Epoch: 7 | Validation Loss: 0.66966 >|> ~| Epoch: 8 | Validation Loss: 0.61713 >|> ~| Epoch: 9 | Validation Loss: 0.57910 >|> ~| Epoch: 10 | Validation Loss: 0.56054 >|> ~| Epoch: 11 | Validation Loss: 0.55427 >|> ~| Epoch: 12 | Validation Loss: 0.50306 >|> ~| Epoch: 13 | Validation Loss: 0.49788 >|> ~| Epoch: 14 | Validation Loss: 0.49993 >|> ~| Epoch: 15 | Validation Loss: 0.48223 >|> ~| Epoch: 16 | Validation Loss: 0.47493 >|> ~| Epoch: 17 | Validation Loss: 0.46456 >|> ~| Epoch: 18 | Validation Loss: 0.46504 >|> ~| Epoch: 19 | Validation Loss: 0.46375 >|> ~| Epoch: 20 | Validation Loss: 0.46414 >|> ~| Epoch: 21 | Validation Loss: 0.46580 >|> ~| Epoch: 22 | Validation Loss: 0.46525 >|> ~| Epoch: 23 | Validation Loss: 0.46411 >|> ~| Epoch: 24 | Validation Loss: 0.47405 >|> ~| Epoch: 25 | Validation Loss: 0.46154 >|> ~| Epoch: 26 | Validation Loss: 0.45742 >|> ~| Epoch: 27 | Validation Loss: 0.45486 >|> ~| Epoch: 28 | Validation Loss: 0.46553 >|> ~| Epoch: 29 | Validation Loss: 0.46568 >|> ~| Epoch: 30 | Validation Loss: 0.45212 >|> ~| Epoch: 31 | Validation Loss: 0.46168 >|> ~| Epoch: 32 | Validation Loss: 0.45224 >|> ~| Epoch: 33 | Validation Loss: 0.44911 >|> ~| Epoch: 34 | Validation Loss: 0.45225 >|> ~| Epoch: 35 | Validation Loss: 0.45049 >|> ~| Epoch: 36 | Validation Loss: 0.45651 >|> ~| Epoch: 37 | Validation Loss: 0.45275 >|> ~| Epoch: 38 | Validation Loss: 0.45328 >|> ~| Epoch: 39 | Validation Loss: 0.44404 >|> ~| Epoch: 40 | Validation Loss: 0.44117 >|> ~| Epoch: 41 | Validation Loss: 0.44368 >|> ~| Epoch: 42 | Validation Loss: 0.45791 >|> ~| Epoch: 43 | Validation Loss: 0.45383 >|> ~| Epoch: 44 | Validation Loss: 0.45407 >|> ~| Epoch: 45 | Validation Loss: 0.45576 >|> ~| Epoch: 46 | Validation Loss: 0.44717 >|> ~| Epoch: 47 | Validation Loss: 0.45006 >|> ~| Epoch: 48 | Validation Loss: 0.44817 >|> ~| Epoch: 49 | Validation Loss: 0.46272 >|> Restoring model weights from the end of the best epoch. ~| Epoch: 50 | Validation Loss: 0.44152 >|> Epoch 00050: early stopping
plot_learning_curve(h2)
loss, acc = model2.evaluate(X_test, y_test)
print("Testing Accuracy: ", acc*100)
15/15 [==============================] - 0s 2ms/step - loss: 0.5412 - acc: 0.8125 Testing Accuracy: 81.25
y_pred = model2.predict_classes(X_test)
y_classes = [np.argmax(y, axis=None, out=None) for y in y_test]
print(classification_report(y_pred,y_classes))
precision recall f1-score support
1 0.00 0.00 0.00 0
2 1.00 0.81 0.90 480
3 0.00 0.00 0.00 0
accuracy 0.81 480
macro avg 0.33 0.27 0.30 480
weighted avg 1.00 0.81 0.90 480
filename = 'Signal_Strength_Classifier'
model2.save(f"{filename}.h5")
# some time later...
# load the model from disk
from tensorflow.keras.models import load_model
# load model
model = load_model(f"{filename}.h5")
# summarize model.
model.summary()
# Hence, this model can be loaded and re-used anywhere with similar datasets
Model: "sequential_1" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense_3 (Dense) (None, 100) 800 _________________________________________________________________ dense_4 (Dense) (None, 50) 5050 _________________________________________________________________ dropout_2 (Dropout) (None, 50) 0 _________________________________________________________________ dense_5 (Dense) (None, 4) 204 ================================================================= Total params: 6,054 Trainable params: 6,054 Non-trainable params: 0 _________________________________________________________________